#region Using Statements
using System;
using System.Reflection; 
using System.Deployment;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using SkyBurner.Screens;
#endregion

namespace SkyBurner
{
    public class BaseGame : Microsoft.Xna.Framework.Game
    {
        protected GraphicsDeviceManager m_graphicsDeviceManager;
        protected ContentManager m_contentManager;
        protected UserInputState m_userInputState;
        protected Collection<BaseObject> m_gameObjects = new Collection<BaseObject>();
        protected SoundManager m_soundManager;
        protected BitmapFont m_bitmapFont;
        protected int m_nFPS;
        protected int m_nFrameCount;
        protected float m_fLastMillisecond;
        protected String m_texturePath;
        protected ShadersManager m_shadersManager;
        protected Console m_Console;
        protected RenderTarget2D m_offscreenRenderTarget;
        protected PostScreenEffectsManager m_postScreenEffectsManager;
        protected Version m_Version;
        protected GUIManager m_GUIManager;         
        protected ScreenManager m_screenManager;
        protected float m_fCurrentTick;
        protected SpriteBatch m_spriteBatch;
        protected bool m_bPause;

        public GraphicsDevice GraphicsDevice
        {
            get { return m_graphicsDeviceManager.GraphicsDevice; }
        }

        public ContentManager ContentManager
        {
            get { return m_contentManager; }
        }

        public UserInputState UserInputState
        {
            get { return m_userInputState; }
        }

        public SoundManager SoundManager
        {
            get { return m_soundManager; }
        }

        public BitmapFont BitmapFont
        {
            get { return m_bitmapFont; }
        }

        public ShadersManager ShadersManager
        {
            get { return m_shadersManager; }
        }

        public int FPS
        {
            get { return m_nFPS; }
        }

        public String TexturePath
        {
            get { return m_texturePath; }
        }

        public Console Console
        {
            get { return m_Console; }
        }

        public RenderTarget2D OffscreenRenderTarget
        {
            get { return m_offscreenRenderTarget; }
        }

        public PostScreenEffectsManager PostScreenEffectsManager
        {
            get { return m_postScreenEffectsManager; }
        }

        public Version Version
        {
            get { return m_Version; }
        }

        public GUIManager GUIManager
        {
            get { return m_GUIManager; }
        }

        public ScreenManager ScreenManager
        {
            get { return m_screenManager; }
        }

        public SpriteBatch SpriteBatch
        {
            get { return m_spriteBatch; }
        }

        public bool Pause
        {
            get { return m_bPause; }
            set { m_bPause = value; }
        }

        public BaseGame()
        {
            // init our toys...
            m_graphicsDeviceManager = new GraphicsDeviceManager(this);
            m_contentManager = new ContentManager(Services);

            m_bitmapFont = null;
            m_nFPS = 0;
            m_nFrameCount = 0;
            m_fLastMillisecond = 0.0f;
            m_fCurrentTick = 0.0f;
            m_texturePath = "";
            m_bPause = false;
            m_Version = Assembly.GetExecutingAssembly().GetName().Version;

            m_graphicsDeviceManager.DeviceReset += new EventHandler(OnDeviceReset);
        }

        public void RegisterObject(BaseObject pBaseObject)
        {
            m_gameObjects.Add(pBaseObject);
        }

        public void UnregisterObject(BaseObject pBaseObject)
        {
            m_gameObjects.Remove(pBaseObject);
        }

        protected void OnDeviceReset(object sender, EventArgs e)
        {
            // recreate our toys...
            m_offscreenRenderTarget = new RenderTarget2D(GraphicsDevice, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height, 1, SurfaceFormat.Color);

            // restore all our toys
            foreach (BaseObject baseObject in m_gameObjects)
                baseObject.OnDeviceReset();          
        }

        protected override void OnActivated(object sender, EventArgs args)
        {
            base.OnActivated(sender, args);
        }

        protected override void OnDeactivated(object sender, EventArgs args)
        {
            base.OnDeactivated(sender, args);
        }

        protected override void LoadGraphicsContent(bool loadAllContent)
        {
            base.LoadGraphicsContent(loadAllContent);
        }

        protected override void UnloadGraphicsContent(bool unloadAllContent)
        {
            base.UnloadGraphicsContent(unloadAllContent);
        }

        protected override void Initialize()
        {
            base.Initialize();

            // initialize all our toys...
            m_Console = new Console(this, "Data\\Textures\\console_background", "Data\\Textures\\Courier New");
            m_userInputState = new UserInputState();
            m_soundManager = new SoundManager(this);
            m_shadersManager = new ShadersManager(this);
            m_offscreenRenderTarget = new RenderTarget2D(GraphicsDevice, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height, 1, SurfaceFormat.Color);
            m_postScreenEffectsManager = new PostScreenEffectsManager(this);
            m_GUIManager = new GUIManager(this);
            m_screenManager = new ScreenManager(this);
            m_spriteBatch = new SpriteBatch(GraphicsDevice);

            Components.Add(m_screenManager);

            IsFixedTimeStep = false;
        }

        protected override void Update(GameTime gameTime)
        {
            // process user input...
            m_userInputState.ProcessEx(gameTime);
            if (m_userInputState.IsUserAction(UserAction.Start))
                m_bPause = !m_bPause;

            if (!m_GUIManager.IsPopupVisible)
            {
                if (!m_bPause)
                {
                    // update components...
                    base.Update(gameTime);
                }
            }

            // update sounds...
            m_soundManager.Update();

            // update GUI...
            m_GUIManager.Update(gameTime);

            // update console
            if (m_Console.Enabled)
            {
                m_Console.Update(gameTime);
                if (m_userInputState.IsUserAction(UserAction.RightShoulder))
                    m_Console.Visible = !m_Console.Visible;
            }

            // calc fps
            m_nFrameCount++;
            if ((gameTime.TotalRealTime.TotalMilliseconds - m_fLastMillisecond) >= 1000.0f)
            {
                m_fLastMillisecond = (float)gameTime.TotalRealTime.TotalMilliseconds;
                m_nFPS = m_nFrameCount;
                m_nFrameCount = 0;
            }

            m_userInputState.Reset();
        }

        protected override void Draw(GameTime gameTime)
        {
            if (!m_bPause)
            {
                GraphicsDevice.SetRenderTarget(0, OffscreenRenderTarget);
                GraphicsDevice.Clear(Color.Black);

                // draw components...
                base.Draw(gameTime);

                GraphicsDevice.ResolveRenderTarget(0);
                GraphicsDevice.SetRenderTarget(0, null);
            }

            // draw on screen...
            m_postScreenEffectsManager.Draw(gameTime, m_offscreenRenderTarget.GetTexture());

            // draw GUI...
            m_GUIManager.Draw(gameTime);

            // draw the console...
            if (m_Console.Enabled)
                m_Console.Draw(gameTime);
        }
    }
}
